<%
'######################################################################
'## App.View.asp
'## -------------------------------------------------------------------
'## Feature     :   App View Core
'## Version     :   v1.0.0
'## Author      :   Lajox (lajox@19www.com)
'## Update Date :   2014/12/02 21:55
'## HomePage	:   http://www.19www.com
'## -------------------------------------------------------------------
'## Description :   App View 视图层
'######################################################################

Class Cls_App_View

	Private s_dictName, s_charset, s_tpldir, s_theme, s_path, s_layerfile, s_file, s_fileExt, s_html, s_final
	Private s_path_root, s_path_static ,s_path_js, s_path_css, s_path_img, s_path_upload
	Private b_debug, b_asp, b_parsed, b_layerout, b_locate
	Private i_pageSize, s_pageMark
	Private i_loadtype, i_tag, i_custom_tag
	Public DicLabel, RsData, Pager, TagLib, TagCom, TagCms

	Private Sub Class_Initialize()
		On Error Resume Next
		b_parsed = False
		s_charset = App.CharSet '编码设置
		s_dictName = AB.dictName
		b_debug = App.Debug
		b_asp = App.AspEnable
		b_layerout = App.LayerOut
		b_locate = App.Locate
		s_tpldir = App.TplPath
		s_theme = AB.C.IIF(Trim(App.Default_Theme)<>"",Trim(App.Default_Theme),"default")
		s_path = s_tpldir & s_theme & "/" & GROUP_NAME
		s_file = ""
		s_fileExt = ".html"
		s_layerfile = "layer.html"
		i_loadtype = 1 '默认从文件载入
		i_tag = 0
		i_custom_tag = 3 '自定义标签嵌套层数
		'---
		s_path_root = App.RootPath()
		s_path_static = FixPath(App.StaticPath)
		s_path_js = FixPath(App.JsPath)
		s_path_css = FixPath(App.CssPath)
		s_path_img = FixPath(App.ImgPath)
		s_path_upload =  FixPath(App.UploadPath)
		'---
		Set DicLabel = AB.C.Dict()
		Set RsData = AB.C.Dict()
		Set TagLib = AB.C.Dict()
		Set o_taglib = AB.C.Dict()
		AB.Use "E" : AB.E.Use "Md5"
		AB.Use "Fso" : AB.Fso.CharSet = s_charset
		i_pageSize = 10 '分页数
		s_pageMark = "p" '分页标识
		AB.Use "Pager" : Set Pager = AB.Pager.New '使用AspBox分页插件
		Pager.Param = "p"
		Pager.Url = ""
		Pager.PageSize = i_pageSize
		Pager.Format = "<div class=""pagerbar"">{first} {prev} {list} {next} {last}</div>"
		Pager.Style = ""
		' Pager.Css = "" &_
			' ".pagerbar { text-align:center;padding:16px 0;height:30px;line-height:20px;font-size:12px;margin: 0; color:#555; }" &_
			' ".pagerbar a,.pagerbar span{display:inline-block;padding:5px 0;height:20px; text-decoration:none}" &_
			' ".pagerbar a{border:1px solid #C2D5E3; background-color:#fff;padding:0 10px}" &_
			' ".pagerbar a:link,.pagerbar a:visited{color:#555;}" &_
			' ".pagerbar a.up,.pagerbar a.next{_font-size:12px}" &_
			' ".pagerbar span.current,.pagerbar a:hover{border:1px solid #C2D5E3; color:#333;padding:0 10px;background-color:#E5EDF2;text-decoration:none}" &_
			' ".pagerbar span.first, .pagerbar span.last{ border:1px solid #C2D5E3;background-color:#f6f6f6;padding:0 10px }" &_
			' ".pagerbar span{padding:0 10px}"
		Pager.addStyle "first{display:show;class:first;dis-tag:span;text:首 页;}"
		Pager.addStyle "prev{display:auto;class:prev;dis-tag:span;text:上一页;}"
		Pager.addStyle "next{display:auto;class:next;dis-tag:span;text:下一页;}"
		Pager.addStyle "last{display:show;class:last;dis-tag:span;text:尾 页;}"
		Pager.addStyle "list{display:show;curr-tag:span;curr-class:current;link-text:'$n';link-class:'';link-space:' ';dot-val:'..';dot-for:txt#xy;index:4|4;min:9;}"
		On Error GoTo 0
	End Sub

	Private Sub Class_Terminate()
		Set DicLabel = Nothing
		Set RsData = Nothing
		Set TagLib = Nothing
		Set TagCom = Nothing
		Set TagCms = Nothing
		Set Pager = Nothing
	End Sub

	Public Property Let [Debug](ByVal b)
		b_debug = b
	End Property
	Public Property Get [Debug]
		[Debug] = b_debug
	End Property

	'设置使用字符编码
	Public Property Let CharSet(ByVal v)
		s_charset = v
	End Property

	Public Property Get [CharSet]()
		[CharSet] = s_charset
	End Property

	Public Property Let PageSize(ByVal n)
		If Not IsNumeric(n) Then n = 0
		If CLng(n)<=0 Then n = 10
		i_pagesize = CLng(n)
	End Property
	Public Property Get PageSize()
		PageSize = i_pagesize
	End Property

	Public Property Let PageMark(ByVal s)
		If IsNull(s) Or Trim(s) = "" Then s = "p"
		s_pageMark = s
	End Property
	Public Property Get PageMark()
		If IsNull(s_pageMark) Or Trim(s_pageMark) = "" Then s_pageMark = "p"
		PageMark = s_pageMark
	End Property

	'模板存放总路径
	Public Property Get TplDir
		TplDir = s_tpldir
	End Property

	Public Property Let TplDir(ByVal f)
		If Right(f,1)<>"/" Then f = f & "/"
		s_tpldir = f
		s_path = FixPath(s_tpldir & s_theme & "/" & GROUP_NAME)
	End Property

	'模板主题目录名
	Public Property Get Theme
		Theme = s_theme
	End Property

	Public Property Let Theme(ByVal f)
		s_theme = f
		s_path = FixPath(s_tpldir & s_theme & "/" & GROUP_NAME)
	End Property

	Public Property Let PathRoot(ByVal s)
		s = Trim(s)
		If Right(s,1)="/" Then s = Left(s,Len(s)-1)
		s_path_root = s
	End Property
	Public Property Get Path_Root()
		Path_Root = s_path_root
	End Property

	Public Property Get Path_Theme
		Path_Theme = FixPath(s_tpldir & s_theme)
	End Property

	Public Property Get Path_TMPL
		Path_TMPL = FixPath(s_tpldir & s_theme & "/" & GROUP_NAME)
	End Property

	Public Property Get Path_Assets
		Path_Assets = FixPath(s_tpldir & s_theme & "/" & GROUP_NAME & AB.C.IIF(b_locate, "/" & MODULE_NAME, ""))
	End Property

	Public Property Let Path_Static(ByVal s)
		s_path_static = FixPath(s)
	End Property
	Public Property Get Path_Static()
		Path_Static = s_path_static
	End Property

	Public Property Let Path_Js(ByVal s)
		s_path_js = FixPath(s)
	End Property
	Public Property Get Path_Js()
		Path_Js = s_path_js
	End Property

	Public Property Let Path_Css(ByVal s)
		s_path_css = FixPath(s)
	End Property
	Public Property Get Path_Css()
		Path_Css = s_path_css
	End Property

	Public Property Let Path_IMG(ByVal s)
		s_path_img = FixPath(s)
	End Property
	Public Property Get Path_IMG()
		Path_IMG = s_path_img
	End Property

	Public Property Let Path_Upload(ByVal s)
		s_path_upload = FixPath(s)
	End Property
	Public Property Get Path_Upload()
		Path_Upload = s_path_upload
	End Property

	'模板文件所在文件夹
	Public Property Get TplPath
		's_path = FixPath(s_tpldir & s_theme & "/" & GROUP_NAME)
		s_path = FixPath(s_path)
		TplPath = s_path
	End Property
	Public Property Let TplPath(ByVal f)
		If Trim(f)<>"" Then s_path = FixPath(f)
	End Property

	'设置是否定位模板目录
	Public Property Let Locate(ByVal b)
		b_locate = b
	End Property
	Public Property Get Locate
		Locate = b_locate
	End Property

	'设置是否加载layerout文件
	Public Property Let LayerOut(ByVal b)
		b_layerout = b
	End Property
	Public Property Get LayerOut
		LayerOut = b_layerout
	End Property

	'设置layerout文件
	Public Property Get LayerFile
		LayerFile = s_layerfile
	End Property
	Public Property Let LayerFile(ByVal f)
		s_layerfile = Trim(f)
	End Property

	'设置模板文件格式(文件名后缀)
	Public Property Get TplExt
		TplExt = s_fileExt
	End Property
	Public Property Let TplExt(ByVal f)
		f = Trim(f)
		f = AB.C.IIF(f="", ".html", f)
		If f<>"" And InStr(f,".")<=0 Then f = "."& f
		s_fileExt = f
	End Property

	'从模板文件里载入内容
	Public Property Get TplFile
		TplFile = s_file
	End Property
	Public Property Let TplFile(ByVal f)
		i_loadtype = 1
		f = Trim(f)
		If f="" Then f = ACTION_NAME
		If AB.Fso.ExtOf(f)<>s_fileExt Then f = f & s_fileExt
		s_file = f
		If Left(f,1)="/" Then
			s_html = LoadTpl(f)
		Else
			s_html = LoadTpl(FixPath(s_path) & "/" & AB.C.IIF(b_locate, MODULE_NAME & "/" & f, f))
		End If
		s_html = LayerStr(s_html) '加载Layerout模板内容
		s_final = Me.GetHtml()
	End Property

	'加载内容模板(注：设置的模板文件 和 内容模板，二者只取其一，以最后一次为准)
	Public Property Let [Source](ByVal s)
		LoadStr(s)
	End Property

	'赋值
	Public Property Let d(ByVal s,ByVal v)
		Me.Assign s, v
	End Property

	Public Default Sub Assign(ByVal s, ByVal v)
		On Error Resume Next
		Dim i,j,a,b,tmp,ary : ary = AB.C.RegSplit(s,"\s*,\s*",0)
		For i = 0 To Ubound(ary) '多标签赋值
			s = Lcase(ary(i))
			Select Case VarType(v)
				Case vbObject '9
					Select Case TypeName(v)
						Case "Recordset" '记录集
							''If v.State And Not v.eof Then
								''Set DicLabel(s) = RsToDic(v,DicLabel)
							''End If
							' If v.State Then Set DicLabel(s) = v
							' If AB.C.Has(v) Then
								' For j = 0 To v.Fields.Count - 1
									' Assign s & "." & v.Fields(j).Name, v.Fields(j).Value
									' Assign s & "." & ij, v.Fields(j).Value
								' Next
							' End If
							Set DicLabel(s) = v
							'Set DicLabel(s) = v.Clone()
						Case "Dictionary" '字典
							' Set DicLabel(s) = v
							' If AB.C.Has(v) Then
								' For Each j In v
									' If AB.C.RegTest(j, "^[\w]+$") Then
										' Assign s & "." & j, v.Item(j)
									' End If
								' Next
							' End If
							Set DicLabel(s) = v
						Case "Cls_AB_List"
							If v.Size > 0 Then
								''Set DicLabel(s) = RsToDic(v,DicLabel)
								Set DicLabel(s) = v
								For j = 0 To v.End
									Assign s & "." & j, v(j)
								Next
							End If
						Case Else
							Set DicLabel(s) = v
					End Select
				Case vbArray,8194,8204,8209 '数组
					DicLabel(s) = v
				Case Else
					If IsObject(v) Then Set DicLabel(s) = v Else DicLabel(s) = v
			End Select
		Next
		UpdateDicLabel()
		On Error Goto 0
	End Sub

	Public Sub Tag(ByVal s, ByVal v)
		Assign s, v
	End Sub

	'标签替换为副模板内容
	Public Sub TagFile(ByVal s, ByVal f)
		If AB.Fso.ExtOf(f)<>s_fileExt Then f = f & s_fileExt
		Assign s, LoadTpl(FixPath(s_path) & "/" & AB.C.IIF(b_locate, MODULE_NAME & "/" & f, f))
	End Sub

	Public Sub LoadStr(ByVal s)
		i_loadtype = 2 
		s_html = s
	End Sub

	'e.g. App.View.Display("index.html")
	Public Sub Display(ByVal f)
		f = Trim(f)
		If f="" Then f = ACTION_NAME
		If AB.Fso.ExtOf(f)<>s_fileExt Then f = f & s_fileExt
		s_file = f
		''s_html = AB.C.IncRead(s_path & f)
		If Left(f,1)="/" Then
			s_html = LoadTpl(f)
		Else
			s_html = LoadTpl(FixPath(s_path) & "/" & AB.C.IIF(b_locate, MODULE_NAME & "/" & f, f))
		End If
		s_html = LayerStr(s_html) '加载Layerout模板内容
		Combine(s_html)
	End Sub

	'e.g. App.View.TplFile = "index.html" : App.View.Show()
	Public Sub Show()
		''Combine(s_html)
		If Not b_parsed Then
			Me.TplFile = ""
			s_final = Me.GetHtml()
		End If
		AB.C.Print s_final
	End Sub

	'加载Layerout模板内容
	Public Function LayerStr(ByVal str)
		On Error Resume Next
		Dim tmp
		If AB.C.RegTest(str, "(<!--[\s]*)?\{?__NOLAYOUT__\}?([\s]*-->)?") Then
			str = AB.C.RegReplace(str, "(<!--[\s]*)?\{?__NOLAYOUT__\}?([\s]*-->)?", "")
		ElseIf b_layerout And s_layerfile <> "" Then
			If AB.C.IsFile(FixPath(s_path) & "/" & s_layerfile) Then
				tmp = LoadTpl(FixPath(s_path) & "/" & s_layerfile)
				'tmp = AB.C.RegReplace(tmp, "(<!--[\s]*)?\{?__CONTENT__\}?([\s]*-->)?", str) '不用正则，因可能出错
				tmp = AB.C.RP(tmp, "<!--{__CONTENT__}-->", str)
				tmp = AB.C.RP(tmp, "{__CONTENT__}", str)
				tmp = AB.C.RP(tmp, "__CONTENT__", str)
				str = tmp
			End If
		End If
		LayerStr = str
		On Error Goto 0
	End Function

	'e.g. 载入模板文件标签
	'1: {include "a.tpl"} 或 {include 'a.tpl'}  //无引号, 单引号或双引号都行
	'2: {include('a.tpl')} 或 {include ( 'a.tpl' ) }  //使用括号
	'3: {template 'a.tpl'} 或 {template('a.tpl')}

	Public Function LoadTpl(ByVal p)
		LoadTpl = LoadInc(p, "")
	End Function

	Public Function Parse(ByVal str)
		On Error Resume Next
		Dim Matches, Match, rule, rulex, tag, condi, Matches2, Match2, f, pa, p
		Dim tmp, var, x1, x2, addStr, add, symbol : add = 1
		str = AB.C.RP(str, Array("\\","\{","\}"), Array(Chr(1),Chr(2),Chr(3)) ) '替换转义字符
		'=== 解析用户自定义标签
		str = CustomTag(str)
		'=== 解析原样输出标签： {@literal}..{/@literal}
		rule = "(<!--[\s]*)?\{@(literal)\s*\}([\s\S]*?)(\{\/@\2\s*\})([\s]*-->)?"
		If AB.C.RegTest(str, rule) Then
			Set Matches = AB.C.RegMatch(str, rule)
			For Each Match In Matches
				tmp = Trim(Match.SubMatches(2))
				tmp = AB.C.RP(tmp, Array("{","}"), Array(Chr(2),Chr(3)) ) '替换转义字符
				str = AB.C.RP(str, Match.Value, tmp)
			Next
			Set Matches = Nothing
		End If
		'=== 公共标签解析 b
		rule = "(<!--[\s]*)?\{?__([A-Z][A-Z0-9]*)__\}?([\s]*-->)?"
		rulex = "(<!--[\s]*)?\{?__@@@__\}?([\s]*-->)?"
		Set Matches = AB.C.RegMatch(str, rule)
		For Each Match In Matches
			var = Trim(Match.SubMatches(1))
			If var = "CHARSET" Then
				'str = AB.C.RP(str, Match.Value, App.CharSet )
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), App.CharSet)
			ElseIf var = "ROOTURL" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), RootURL())
			ElseIf var = "URL" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), URL())
			ElseIf var = "SELF" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), SELF())
			ElseIf var = "ROOT" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), s_path_root)
			ElseIf var = "PUBLIC" Or var = "STATIC" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), s_path_static)
			ElseIf var = "JS" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), s_path_js)
			ElseIf var = "CSS" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), s_path_css)
			ElseIf var = "IMG" Or var = "IMAGE" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), s_path_img)
			ElseIf var = "UPLOAD" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), s_path_upload)
			ElseIf var = "THEME" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), Me.Path_Theme)
			ElseIf var = "TMPL" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), Me.Path_TMPL)
			ElseIf var = "ASSETS" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), Me.Path_Assets)
			ElseIf var = "M" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), REQ_M)
			ElseIf var = "C" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), REQ_C)
			ElseIf var = "A" Then
				str = AB.C.RegReplace(str, AB.C.RP(rulex,"@@@",var), REQ_A)
			Else
				'str = AB.C.RP(str, Match.Value, "")
			End If
		Next
		Set Matches = Nothing
		rule = "(<!--[\s]*)?\{(include|template)[:|\s]?(.+?)\}([\s]*-->)?"
		If AB.C.RegTest(str,rule) Then
			Set Matches = AB.C.RegMatch(str,rule)
			For Each Match In Matches
				f = Match.SubMatches(2)
				f = SubTplPath(f)
				f = FixPath(s_path) & "/" & AB.C.IIF(b_locate, MODULE_NAME & "/" & f, f)
				p = "" : pa = AB.C.IIF(Left(f,1)="/","",p)
				If AB.C.isNul(p) Then
					If Instr(f,"/")>0 Then p = Left(f,InstrRev(f,"/"))
				Else
					If Instr(f,"/")>0 Then p = pa & Left(f,InstrRev(f,"/"))
				End If
				temp = LoadInc(f, p)
				str = AB.C.RP(str, Match.Value, temp)
			Next
			Set Matches = Nothing
		End If
		'-- 解析asp标签、自增/自减标签
		str = AB.C.RegReplace ( str, "\{\s*\$?(\w+)\+\+\s*\}", "<"&"% $1 = $1 + 1 %"&">" )
		str = AB.C.RegReplace ( str, "\{\s*\$?(\w+)\-\-\s*\}", "<"&"% $1 = $1 - 1 %"&">" )
		str = AB.C.RegReplace ( str, "\{asp\s+(\w+)\+\+\s*\}", "<"&"% $1 = $1 + 1 %"&">" )
		str = AB.C.RegReplace ( str, "\{asp\s+(\w+)\-\-\s*\}", "<"&"% $1 = $1 - 1 %"&">" )
		Set Matches = AB.C.RegMatch(str, "\{asp\s*\}([\s\S]*?)\{\/asp\}")
		For Each Match In Matches
			tmp = Match.SubMatches(0)
			'tmp = AB.C.RegReplace( tmp, "(['""])([^\1]*?)\1", """$2""" )
			str = AB.C.RP( str, Match.Value, "{asp}"& tmp & "{/asp}" )
		Next
		Set Matches = Nothing
		str = AB.C.RegReplace ( str, "\{asp\s*\}", "<"&"% " )
		str = AB.C.RegReplace ( str, "\{\/asp\}", " %"&">" )
		'str = AB.C.RegReplace ( str, "\{asp\s+(.+?)\}", "<"&"% $1 %"&">" )
		'Set Matches = AB.C.RegMatch(str, "\{asp\s+(.+?)\}")
		Set Matches = AB.C.RegMatch(str, "\{(asp\s+|%)(.+?)\s*%?\}")
		For Each Match In Matches
			tmp = Match.SubMatches(1)
			tmp = AB.C.RegReplace( tmp, "(['""])([^\1]*?)\1", """$2""" )
			str = AB.C.RP( str, Match.Value, "<"&"% "& tmp & " %"&">" )
		Next
		Set Matches = Nothing
		str = AB.C.RegReplace ( str, "\{\s*\$?(\w+)\s*([\+\-])\s*(\d+)\s*\}", "<"&"%=$1$2$3%"&">" )
		'-- 解析if标签
		''str = AB.C.RegReplace ( str, "\{(if|elseif)\s+(.+?)\}", "<"&"% $1 ( $2 ) Then %"&">" )
		Set Matches = AB.C.RegMatch(str, "{(if|elseif)\s+(.+?)}")
		For Each Match In Matches
			tag = Match.SubMatches(0)
			condi = Match.SubMatches(1)
			condi = AB.C.RP(condi, "&&", " And ")
			condi = AB.C.RP(condi, "||", " Or ")
			condi = AB.C.RP(condi, "==", "=")
			condi = AB.C.RP(condi, "!=", "<>")
			condi = AB.C.RegReplace( condi, "(['""])([^\1]*?)\1", """$2""" )
			str = AB.C.RP( str, Match.Value, "<"&"% "& AB.D.MCase(tag) &" ( "& condi &" ) Then %"&">" )
		Next
		Set Matches = Nothing
		str = AB.C.RegReplace ( str, "\{else\}", "<"&"% Else %"&">" )
		str = AB.C.RegReplace ( str, "\{\/if\}", "<"&"% End If %"&">" )
		'-- 解析switch标签: {switch a}{case 'a'}..{case 'b'}..{case else}..{/switch}
		'str = AB.C.RegReplace ( str, "\{switch\s+(.+?)\}", "<"&"% Select Case $1 %"&">" )
		'str = AB.C.RegReplace ( str, "\{case\s+(.+?)\}", "<"&"% Case $1 %"&">" )
		str = AB.C.RegReplace ( str, "\{switch\s+(.+?)\}[\S\s]+?\{case\s+(.+?)\}", "{switch $1}{case $2}" ) '清空{switch}标签与{case}标签之间的内容，防出错
		str = AB.C.RegReplace ( str, "\<"&"%\s*Select\s+(.+?)\s*%"&"\>[\S\s]+?\<"&"%\s*Case\s+(.+?)\s*%"&"\>", "<"&"% Select $1 %"&"><"&"% Case $2 %"&">" )
		Set Matches = AB.C.RegMatch(str, "{(switch|case)\s+(.+?)}")
		For Each Match In Matches
			tag = Match.SubMatches(0)
			condi = Trim(Match.SubMatches(1))
			condi = AB.C.RegReplace( condi, "(['""])([^\1]*?)\1", """$2""" )
			If tag="switch" Then
				str = AB.C.RP( str, Match.Value, "<"&"% Select Case "& condi &" %"&">" )
			Else
				If LCase(condi)="else" Then condi = "Else"
				str = AB.C.RP( str, Match.Value, "<"&"% Case "& condi &" %"&">" )
			End If
		Next
		Set Matches = Nothing
		str = AB.C.RegReplace ( str, "\{\/switch\}", "<"&"% End Select %"&">" )
		'-- 循环
		'a. foreach循环 tpl: {foreach i d}..{/foreach} === asp: foreach i in d .. next
		'str = AB.C.RegReplace( str, "\{foreach\s+(.+?)\s+(.+?)\}","<"&"% For Each $1 in $2 %"&">" )
		str = AB.C.RegReplace( str, "\{foreach\s+(.+?)\s+(.+?)\}","<"&"% If Not AB.C.IsNul($2) Then %"&"><"&"% For Each $1 in $2 %"&">" )
		'str = AB.C.RegReplace( str, "\{\/foreach\}","<"&"% Next %"&">" )
		str = AB.C.RegReplace( str, "\{\/foreach\}","<"&"% Next %"&"><"&"% End If %"&">" )
		'b. while循环 tpl: {asp i=8}{while i>0}..{asp i--}{/while} === asp: while i>0.. i=i-1.. wend
		str = AB.C.RegReplace( str, "\{while\s+(.+?)\s*\}","<"&"% While $1 %"&">" )
		str = AB.C.RegReplace( str, "\{\/while\}","<"&"% Wend %"&">" )
		'c. loop循环 tpl: {asp i=8}{loop i>0}..{asp i--}{/loop} === asp: do while i>0.. i=i-1.. loop
		str = AB.C.RegReplace( str, "\{loop\s+(.+?)\s*\}","<"&"% Do While $1 %"&">" )
		str = AB.C.RegReplace( str, "\{\/loop\}","<"&"% Loop %"&">" )
		'{for(i=0; i<10; i=i+1)} .. {/for}
		Set Matches = AB.C.RegMatch(str, "{for\s*\((.+?)\)\s*}")
		For Each Match In Matches
			condi = Match.SubMatches(0)
			Set Matches2 = AB.C.RegMatch(condi, "(\w+)\s*=(.+?);\s*(\1)\s*([=<>]{1,2})(.+?);\s*(.+)?\s*;?")
			For Each Match2 In Matches2
				var = Trim(Match2.SubMatches(0))
				x1 = Trim(Match2.SubMatches(1))
				x2 = Trim(Match2.SubMatches(4))
				symbol = Trim(Match2.SubMatches(3))
				addStr = Trim(Match2.SubMatches(5))
				If symbol="<" Then
					If AB.C.IsNum(x2) Then x2 = CLng(x2) - 1 Else x2 = CDbl(x2) - 1
				ElseIf symbol="<=" Or symbol=">=" Then
					If AB.C.IsNum(x2) Then x2 = CLng(x2) Else x2 = CDbl(x2)
				ElseIf symbol=">" Then
					If AB.C.IsNum(x2) Then x2 = CLng(x2) + 1 Else x2 = CDbl(x2) + 1
				End If
				If addStr<>"" Then
					If AB.C.RegTest(addStr, ""&var&"\+\+") Then
						add = 1
					ElseIf AB.C.RegTest(addStr, ""&var&"\-\-") Then
						add = -1
					ElseIf AB.C.RegTest(addStr, ""&var&"\s*=\s*"&var&"([\+\-]\w+)\s*") Then
						add = AB.C.RegReplace ( addStr, ""&var&"\s*=\s*"&var&"([\+\-]\w+)\s*", "$1" )
						add = Eval(add)
					End If
				Else '缺省则步阶值为1
					add = 1
				End If
			Next
			str = AB.C.RP( str, Match.Value, "<"&"% for "& var &" = "& x1 &" to "& x2 &" step "& add &" %"&">" )
		Next
		Set Matches = Nothing
		str = AB.C.RegReplace( str, "\{for\s+(.+?)\}","<"&"% for $1 %"&">" )
		str = AB.C.RegReplace( str, "\{\/for\}","<"&"% next %"&">" )
		'==== 表单令牌标签
		str = ParseToken(str)
		'==== 注释标签
		str = AB.C.RegReplace(str, "(<!--[\s]*)?\{\*([^\{\}]*?)\*\}([\s]*-->)?", "") '单行注释标签
		str = AB.C.RegReplace(str, "(<!--[\s]*)?\{@(note|comment)\s*\}([\s\S]*?)(\{\/@\2\s*\})([\s]*-->)?", "") '多行注释标签
		'--
		''str = AB.C.RegReplace ( str, "\{\$?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff:]*\(([^{}]*)\))\}", "<"&"%=$1%"&">" ) '单引号错误
		str = AB.C.RegReplace ( str, "\{\$?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}", "<"&"%=$1%"&">" )
		'==== 拓展系统标签
		str = Me.TagLibParse(str) '载入标签解析引擎
		'-----
		str = AB.C.RP(str, Array(Chr(3),Chr(2),Chr(1)), Array("}","{","\") ) '还原转义字符
		Parse = str
		On Error Goto 0
	End Function

	'载入标签解析引擎
	Public Function TagLibParse(ByVal str)
		On Error Resume Next
		Dim fs, list, tag, fp
		'-- 载入系统标准标签解析引擎
		App.Import("App.Core.TagLib.TagCom") '载入系统标签解析引擎
		App.Import("App.Core.TagLib.TagCms") '载入CMS标签解析引擎
		Set TagCom = New Cls_App_TagCom
		Set TagCms = New Cls_App_TagCms
		Set TagLib("tagcom") = TagCom
		Set TagLib("tagcms") = TagCms
		str = TagCom.Parse(str) '系统标签解析
		str = TagCms.Parse(str) 'CMS标签解析
		'-- 用户拓展标签解析引擎
		fs = App.ExtendPath & "TagLib/App.*.asp"
		list = AB.Fso.glob(fs,1)
		If Not AB.C.IsNul(list) Then
			For i = 0 To UBound(list,2)
				fp = list(0,i)
				tag = LCase(AB.C.RegReplace(fp, ".+?[\/\\]App\.(\w+)\.asp", "$1"))
				If AB.C.RegTest(tag,"^\w+$") And AB.C.isFile(fp) And LCase(AB.Fso.ExtOf(fp))=".asp" Then
					If AB.C.isNul(TagLib(tag)) Then
						App.ReadCache fp
						Set TagLib(tag) = Eval("New Cls_App_"& tag &"")
						Execute("str = TagLib("""& tag &""").Parse(str)")
					End If
					If Err.Number <> 0 Then App.Error.Throw 401, Err.Number, Err.Description
				End If
			Next
		End If
		TagLibParse = str
		On Error GoTo 0
	End Function

	'用户自定义标签解析(支持相互嵌套调用) {cmsself:标签名称}
	Public Function CustomTag(ByVal str) '标签解析
		Dim rs, RegEx, Match, tag, rule : rule = "{cmsself:([\S]+?)}"
		'' 屏蔽此写法，数据量一多效率太低
		' Set rs = M("custom_label")().Order("[level] desc, id desc").Fetch()
		' Do While Not rs.Eof
			' IF rs("status")=1 Then
				' str = AB.C.RP(str, Array("\\","\{","\}"), Array(Chr(1),Chr(2),Chr(3)) ) '替换转义字符
				' str = AB.C.RP(str, "{cmsself:"& rs("name") &"}", ""& rs("content") &"")
			' Else
				' str = AB.C.RP(str, "{cmsself:"& rs("name") &"}", "")
			' End IF
			' rs.MoveNext
		' Loop
		'' 改用此写法：
		Set RegEx = AB.C.RegMatch(str,rule)
		For Each Match In RegEx
			tag = Match.SubMatches(0)
			Set rs = M("custom_label")().Top(1).Where("name='"& tag &"'").Fetch()
			IF Not rs.Eof Then
				IF rs("status")=1 Then
					str = AB.C.RP(str, Array("\\","\{","\}"), Array(Chr(1),Chr(2),Chr(3)) ) '替换转义字符
					str = AB.C.RP(str, Match.value, ""& rs("content") &"")
				Else
					str = AB.C.RP(str, Match.value, "")
				End IF
			End IF
		Next
		Set RegEx = Nothing
		If AB.C.isRs(rs) Then rs.close()
		Set rs = Nothing
		i_tag = i_tag + 1
		If AB.C.RegTest(str,rule) Then
			If i_tag < i_custom_tag Then
				str = CustomTag(str)
			End If
		End If
		CustomTag = str
	End Function

	Private Function ParseToken(ByVal str)
		If App.C("token_on")="true" Then
			If Instr(str,"__TOKEN__")>0 Then
				str = AB.C.RP(str, "{__TOKEN__}", BuildToken())
				str = AB.C.RP(str, "__TOKEN__", BuildToken())
			Else
				str = AB.C.RegReplace(str, "<\/form(\s*)>", BuildToken() & "</form>")
			End If
		Else
			str = AB.C.RP(str, "{__TOKEN__}", "")
			str = AB.C.RP(str, "__TOKEN__", "")
		End If
		ParseToken = str
	End Function

	Private Function BuildToken()
		On Error Resume Next
		Dim tokenName, tokenType, tokenKey, tokenValue, token
		App.noCache() '强制不缓存
		tokenName = App.C("token_name")
		tokenType = App.C("token_type")
		tokenKey = AB.E.Md5.To16(URL())
		If Not(Request.Cookies(tokenName).HasKeys) Then
			Response.Cookies(tokenName)(tokenKey) = Empty
		End If
		If Not AB.C.IsNul(Request.Cookies(tokenName)(tokenKey)) Then
			tokenValue = Cstr(Request.Cookies(tokenName)(tokenKey))
		Else
			AB.Use "E"
			If LCase(tokenType)="sha1" Then
				AB.E.Use "SHA1"
				tokenValue = AB.E.SHA1.E(Now())
			ElseIf LCase(tokenType)="aes" Then
				AB.E.Use "Aes"
				AB.E.Aes.Password = "AppToken"
				tokenValue = AB.E.Aes.E(Now())
			ElseIf LCase(tokenType)="base64" Then
				AB.E.Use "Base64"
				tokenValue = AB.E.Base64.E(Now())
			Else '默认md5
				AB.E.Use "Md5"
				tokenValue = AB.E.Md5.To16(Now())
			End If
			Response.Cookies(tokenName)(tokenKey) = tokenValue
		End If
		token = "<input type=""hidden"" name="""& tokenName &""" value="""& tokenKey & "@#@" & tokenValue &""" />"
		BuildToken = token
		On Error Goto 0
	End Function

	'标签解析
	Public Function Combine(ByVal s_a7b8e9d)
		On Error Resume Next
		Dim lbl_a7b8e9d, o_a7b8e9d, v_a7b8e9d, t_a7b8e9d, tmp_a7b8e9d, fp_a7b8e9d
		For Each lbl_a7b8e9d In DicLabel
			If InStr(lbl_a7b8e9d,".")<=0 Then
				ExecuteGlobal " Dim "& lbl_a7b8e9d &" "
				ExecuteGlobal " If IsObject(Me.DicLabel("""&lbl_a7b8e9d&""")) Then Set "& lbl_a7b8e9d &" = Me.DicLabel("""&lbl_a7b8e9d&""") Else "& lbl_a7b8e9d &" = App.View.DicLabel("""&lbl_a7b8e9d&""")"
			End If
		Next
		' For Each lbl_a7b8e9d In DicLabel
			' If InStr(lbl_a7b8e9d,".")>0 Then
				' o_a7b8e9d = AB.C.CLeft(lbl_a7b8e9d, ".")
				' v_a7b8e9d = AB.C.CRight(lbl_a7b8e9d, ".")
				' If IsObject(Eval(o_a7b8e9d)) Then
					' Set t_a7b8e9d = Eval(o_a7b8e9d)
					' If TypeName(t_a7b8e9d) = "Recordset" Or TypeName(t_a7b8e9d) = "Dictionary" Or TypeName(t_a7b8e9d) = "Cls_AB_List" Then
						' tmp_a7b8e9d = o_a7b8e9d & "(" & v_a7b8e9d & ")"
						' ExecuteGlobal " If IsObject(Me.DicLabel("""&lbl_a7b8e9d&""")) Then Set "& tmp_a7b8e9d &" = Me.DicLabel("""&lbl_a7b8e9d&""") Else "& tmp_a7b8e9d &" = Me.DicLabel("""&lbl_a7b8e9d&""")"
					' End If
					' Set t_a7b8e9d = Nothing
				' End If
			' End If
		' Next
		If App.Cache Then
			If i_loadtype = 1 Then
				fp_a7b8e9d = AB.E.Md5.To32(s_file)
			Else
				fp_a7b8e9d = AB.E.Md5.To32(s_html)
			End If
			fp_a7b8e9d = App.CachePath & "tpl/" & fp_a7b8e9d & ".asp"
			If Not AB.C.isFile(fp_a7b8e9d) Then
				s_a7b8e9d = GetTplAssign(s_a7b8e9d)
				If Not ( App.Req("debug")="" Or LCase(App.Req("debug"))="false" Or LCase(App.Req("debug"))="0" ) Then
					s_a7b8e9d = Me.Parse(s_a7b8e9d)
					AB.Trace s_a7b8e9d
					AB.C.End
				End If
				s_a7b8e9d = Me.Parse(s_a7b8e9d)
				s_a7b8e9d = AB.Pub.GetIncCode(s_a7b8e9d,0)
				App.CreateCaches fp_a7b8e9d, s_a7b8e9d
			End If
			AB.C.xInclude(fp_a7b8e9d)
		Else
			s_a7b8e9d = GetTplAssign(s_a7b8e9d)
			If Not ( App.Req("debug")="" Or LCase(App.Req("debug"))="false" Or LCase(App.Req("debug"))="0" ) Then
				s_a7b8e9d = Me.Parse(s_a7b8e9d)
				AB.Trace s_a7b8e9d
				AB.C.End
			End If
			s_a7b8e9d = Me.Parse(s_a7b8e9d)
			s_a7b8e9d = AB.Pub.GetIncCode(s_a7b8e9d,0)
			ExecuteGlobal s_a7b8e9d
		End If
		''AB.C.Print AB.C.GetScriptTime(0)
		'b_parsed = True
		On Error Goto 0
	End Function

	''解析{@assign var="show_dialog" value="1"} 模板传递变量 标签
	Private Function GetTplAssign(ByVal s_O0O00O0)
		On Error Resume Next
		Dim Matches_O0O00O0, Matches2_O0O00O0, Match_O0O00O0, Match2_O0O00O0, var_O0O00O0, val_O0O00O0, cvar_O0O00O0, cval_O0O00O0, t_O0O00O0
		Dim Matches3_O0O00O0, Match3_O0O00O0
		Set Matches_O0O00O0 = AB.C.RegMatch(s_O0O00O0, "\{@assign\s+(.+?)\s*\}")
		For Each Match_O0O00O0 In Matches_O0O00O0
			Set Matches2_O0O00O0 = AB.C.RegMatch(Match_O0O00O0.SubMatches(0), "([a-zA-Z0-9_]+)\s*=\s*(['""]?)([^'""\s]*|[^\2]*?)\2")
			For Each Match2_O0O00O0 In Matches2_O0O00O0
				cvar_O0O00O0 = Trim(Match2_O0O00O0.SubMatches(0))
				cval_O0O00O0 = Match2_O0O00O0.SubMatches(2)
				Select Case LCase(cvar_O0O00O0)
					Case "var"
						var_O0O00O0 = Trim(cval_O0O00O0)
					Case "value"
						val_O0O00O0 = Trim(cval_O0O00O0)
						val_O0O00O0 = AB.C.RP( val_O0O00O0, "\\", Chr(24) ) '替换普通\符号
						val_O0O00O0 = AB.C.RP( val_O0O00O0, "\$", Chr(25) ) '替换普通$符号
						If AB.C.RegTest(val_O0O00O0, "^\$(\w+)$") Then
							val_O0O00O0 = AB.C.RegReplace(val_O0O00O0, "^\$(\w+)$", "$1")
							val_O0O00O0 = Eval(val_O0O00O0)
						ElseIf AB.C.RegTest(val_O0O00O0, "\(?\$(\w+)\)?") Then
							Set Matches3_O0O00O0 = AB.C.RegMatch(val_O0O00O0, "\(?\$(\w+)\)?")
							For Each Match3_O0O00O0 In Matches3_O0O00O0
								val_O0O00O0 = AB.C.RP( val_O0O00O0, Match3_O0O00O0.Value, Eval(Match3_O0O00O0.SubMatches(0)) )
							Next
							Set Matches3_O0O00O0 = Nothing
						End If
						If AB.C.IsNum(val_O0O00O0) Then
							t_O0O00O0 = CLng(val_O0O00O0)
						ElseIf LCase(val_O0O00O0)="true" Or LCase(val_O0O00O0)="false" Then
							t_O0O00O0 = CBool(val_O0O00O0)
						Else
							t_O0O00O0 = val_O0O00O0
							t_O0O00O0 = AB.C.RP( t_O0O00O0, Chr(25), "$" ) '替换普通$符号
							t_O0O00O0 = AB.C.RP( t_O0O00O0, Chr(24), "\" ) '替换普通\符号
						End If
				End Select
			Next
			If IsObject(t_O0O00O0) Then
				ExecuteGlobal " Set "& var_O0O00O0 &" = "& val_O0O00O0 &" "
			Else
				If AB.C.IsInt(t_O0O00O0) Or AB.C.IsNum(t_O0O00O0) Or LCase(t_O0O00O0)="true" Or LCase(t_O0O00O0)="false" Then
					ExecuteGlobal " "& var_O0O00O0 &" = "& t_O0O00O0 &" "
				Else
					ExecuteGlobal " "& var_O0O00O0 &" = """& t_O0O00O0 &""" "
				End If
			End If
			Me.Assign var_O0O00O0, t_O0O00O0
			s_O0O00O0 = AB.C.RP( s_O0O00O0, Match_O0O00O0.Value, "")
		Next
		Set Matches_O0O00O0 = Nothing
		Set Match2_O0O00O0 = Nothing
		GetTplAssign = s_O0O00O0
		On Error Goto 0
	End Function

	'获取模板解析后的内容 e.g. AB.C.Print App.View.GetHtml
	Public Function GetHtml()
		On Error Resume Next
		Dim s_a7b8e9d, lbl_a7b8e9d, o_a7b8e9d, v_a7b8e9d, t_a7b8e9d, tmp_a7b8e9d, fp_a7b8e9d, Abx_s_html
		If b_parsed Then
			GetHtml = s_final
		Else
			For Each lbl_a7b8e9d In DicLabel
				If InStr(lbl_a7b8e9d,".")<=0 Then
					ExecuteGlobal " Dim "& lbl_a7b8e9d &" "
					ExecuteGlobal " If IsObject(Me.DicLabel("""&lbl_a7b8e9d&""")) Then Set "& lbl_a7b8e9d &" = Me.DicLabel("""&lbl_a7b8e9d&""") Else "& lbl_a7b8e9d &" = App.View.DicLabel("""&lbl_a7b8e9d&""")"
				End If
			Next
			' For Each lbl_a7b8e9d In DicLabel
				' If InStr(lbl_a7b8e9d,".")>0 Then
					' o_a7b8e9d = AB.C.CLeft(lbl_a7b8e9d, ".")
					' v_a7b8e9d = AB.C.CRight(lbl_a7b8e9d, ".")
					' If IsObject(Eval(o_a7b8e9d)) Then
						' Set t_a7b8e9d = Eval(o_a7b8e9d)
						' If TypeName(t_a7b8e9d) = "Recordset" Or TypeName(t_a7b8e9d) = "Dictionary" Or TypeName(t_a7b8e9d) = "Cls_AB_List" Then
							' tmp_a7b8e9d = o_a7b8e9d & "(" & v_a7b8e9d & ")"
							' ExecuteGlobal " If IsObject(Me.DicLabel("""&lbl_a7b8e9d&""")) Then Set "& tmp_a7b8e9d &" = Me.DicLabel("""&lbl_a7b8e9d&""") Else "& tmp_a7b8e9d &" = Me.DicLabel("""&lbl_a7b8e9d&""")"
						' End If
						' Set t_a7b8e9d = Nothing
					' End If
				' End If
			' Next
			If App.Cache Then
				If i_loadtype = 1 Then
					fp_a7b8e9d = AB.E.Md5.To32(s_file)
				Else
					fp_a7b8e9d = AB.E.Md5.To32(s_html)
				End If
				fp_a7b8e9d = App.CachePath & "tpl/" & fp_a7b8e9d & ".asp"
				If Not AB.C.isFile(fp_a7b8e9d) Then
					s_a7b8e9d = GetTplAssign(s_html)
					If Not ( App.Req("debug")="" Or LCase(App.Req("debug"))="false" Or LCase(App.Req("debug"))="0" ) Then
						s_a7b8e9d = Me.Parse(s_a7b8e9d)
						AB.Trace s_a7b8e9d
						AB.C.End
					End If
					s_a7b8e9d = Me.Parse(s_a7b8e9d)
					s_a7b8e9d = AB.Pub.GetIncCode(s_a7b8e9d,1)
					App.CreateCaches fp_a7b8e9d, s_a7b8e9d
					Execute s_a7b8e9d
				Else
					s_a7b8e9d = AB.Pub.IncCode(fp_a7b8e9d)
					Execute s_a7b8e9d
				End If
			Else
				s_a7b8e9d = GetTplAssign(s_html)
				If Not ( App.Req("debug")="" Or LCase(App.Req("debug"))="false" Or LCase(App.Req("debug"))="0" ) Then
					s_a7b8e9d = Me.Parse(s_a7b8e9d)
					AB.Trace s_a7b8e9d
					AB.C.End
				End If
				s_a7b8e9d = Me.Parse(s_a7b8e9d)
				s_a7b8e9d = AB.Pub.GetIncCode(s_a7b8e9d,1)
				Execute s_a7b8e9d
			End If
			b_parsed = True
			s_final = Abx_s_html
			GetHtml = Abx_s_html
		End If
		On Error Goto 0
	End Function

	'获取模板解析后的内容 e.g. AB.C.Print App.View.GetTplHtml("a.tpl")
	Public Function GetTplHtml(ByVal p)
		On Error Resume Next
		Dim s_html
		Me.TplFile = p
		s_html = Me.GetHtml()
		GetTplHtml = s_html
		On Error Goto 0
	End Function

	'获取模板变量的值
	Public Function [Get](ByVal p)
		On Error Resume Next
		If Me.DicLabel.Exists(p) Then
			If IsObject(Me.DicLabel(p)) Then Set [Get] = Me.DicLabel(p) Else [Get] = Me.DicLabel(p)
		End If
		On Error Goto 0
	End Function

	'生成模板解析后的内容
	Public Sub SaveAs(ByVal p)
		On Error Resume Next
		Dim str : str = Me.GetHtml()
		Call AB.Fso.CreateFile(p, str)
		On Error Goto 0
	End Sub

	'组装获取对象属性值
	Public Function ObjAttr(ByVal o_a9b8e7d, ByVal v_a9b8e7d, ByVal t_a9b8e7d)
		On Error Resume Next
		Dim tmp_a9b8e7d, oa_a9b8e7d
		If IsObject(Eval(o_a9b8e7d)) And Trim(v_a9b8e7d)<>"" Then
			Set oa_a9b8e7d = Eval(o_a9b8e7d) : v_a9b8e7d = Trim(v_a9b8e7d)
			If (TypeName(oa_a9b8e7d)="Recordset" Or TypeName(oa_a9b8e7d)="Dictionary" Or TypeName(oa_a9b8e7d)="Cls_AB_List") Then
				If Trim(t_a9b8e7d)<>"" Then
					tmp_a9b8e7d = Eval(o_a9b8e7d&"("""&v_a9b8e7d&""")"&Trim(t_a9b8e7d)&"")
				Else
					If IsObject(Eval(o_a9b8e7d&"("""&v_a9b8e7d&""")")) Then Set tmp_a9b8e7d = Eval(o_a9b8e7d&"("""&v_a9b8e7d&""")") Else tmp_a9b8e7d = Eval(o_a9b8e7d&"("""&v_a9b8e7d&""")")
				End If
			Else
				If Trim(t_a9b8e7d)<>"" Then
					tmp_a9b8e7d = Eval(o_a9b8e7d&"."&v_a9b8e7d&""&Trim(t_a9b8e7d)&"")
				Else
					If IsObject(Eval(o_a9b8e7d&"."&v_a9b8e7d)) Then Set tmp_a9b8e7d = Eval(o_a9b8e7d&"."&v_a9b8e7d) Else tmp_a9b8e7d = Eval(o_a9b8e7d&"."&v_a9b8e7d)
				End If
			End If
		Else
			tmp_a9b8e7d = Eval(o_a9b8e7d)
		End If
		If IsObject(tmp_a9b8e7d) Then Set ObjAttr = tmp_a9b8e7d Else ObjAttr = tmp_a9b8e7d
		Set tmp_a9b8e7d = Nothing
		On Error Goto 0
	End Function

	'数组或字典对象的循环读取
	Public Function arrEach(ByVal o, ByVal no, ByVal size, ByVal offset, ByVal rows)
		On Error Resume Next
		Dim oa, FromX, FromY, min, max, total, pNum, start, over : start = 0 : over = 0
		size = CLng(size)
		no = CLng(no)
		If no<=0 Then no = 1
		If IsArray(Eval(o&"")) Or AB.C.IsDict(Eval(o&"")) Then 'Array数组
			If IsObject(Eval(o&"")) Then Set oa = Eval(o&"") Else oa = Eval(o&"")
			If AB.C.IsNul(oa) Then
				FromX = 0 : FromY = 0
			Else
				offset = CLng(offset) '偏移量
				rows = CLng(rows) '取数量
				If offset<0 Then offset = 0
				If rows<0 Then rows = 0
				start = offset
				If rows>0 Then over = offset+rows-1
				If IsArray(oa) Then
					min = LBound(oa)
					max = UBound(oa)
					total = (max - min)+1 '总记录数
				ElseIf AB.C.IsDict(oa) Then
					total = oa.Count '总记录数
					min = 0
					max = total - 1
				End If
				If size>0 Then '有设置分页
					If start<min Then start = min
					If over>max Or over=0 Then over = max
					total = over - start + 1 '重新计算总记录数
					If (total Mod size) = 0 Then
						pNum = CLng(total \ size)
					Else
						pNum = CLng(total \ size) + 1
					End If
					If pNum<=0 Then pNum=0
					FromX = start + (no-1) * size
					FromY = start + no * size - 1
					If FromX>over Then FromX = (pNum - 1) * size + 1
					If FromY>over Then FromY = over
				Else
					If start<min Then start = min
					If over>max Or over=0 Then over = max
					FromX = start
					FromY = over
				End If
				If FromX<min Then FromX = min
				If FromY>max Then FromY = max
			End If
		Else
			FromX = 0 : FromY = 0
		End If
		arrEach = Array(FromX, FromY)
		On Error Goto 0
	End Function

	'计算对象的数据
	Public Function ObjCount(ByVal o)
		On Error Resume Next
		Dim tmp, num : num = 0
		If IsObject(Eval(o&"")) Then
			Set tmp = Eval(o&"")
			If TypeName(tmp)="Recordset" Then 'Rs对象
				num = tmp.RecordCount
			ElseIf AB.C.IsDict(tmp) Then '字典对象
				num = tmp.Count
			End If
			Set tmp = Nothing
		Else
			tmp = Eval(o&"")
			If IsArray(tmp) Then
				num = UBound(tmp) - LBound(tmp)+1
			End If
		End If
		If num<0 Then num = 0
		ObjCount = num
		On Error Goto 0
	End Function

	Private Function LoadInc(ByVal f, ByVal p)
		On Error Resume Next
		Dim h,pa,rule,inc,Match,incFile,incStr,temp
		f = SubTplPath(f)
		pa = AB.C.IIF(Left(f,1)="/","",p)
		If b_asp Then
			h = AB.C.GetInclude( pa & f )
		Else
			h = AB.C.Read( pa & f )
		End If
		rule = "(<!--[\s]*)?\{(include|template)[:|\s]?(.+?)\}([\s]*-->)?"
		If AB.C.RegTest(h,rule) Then
			If AB.C.isNul(p) Then
				If Instr(f,"/")>0 Then p = Left(f,InstrRev(f,"/"))
			Else
				If Instr(f,"/")>0 Then p = pa & Left(f,InstrRev(f,"/"))
			End If
			Set inc = AB.C.RegMatch(h,rule)
			For Each Match In inc
				temp = Match.SubMatches(2)
				incFile = SubTplPath(temp)
				incStr = LoadInc(incFile, p)
				h = AB.C.RP(h,Match,incStr)
			Next
			Set inc = Nothing
		End If
		LoadInc = h
		On Error Goto 0
	End Function

	Private Function SubTplPath(ByVal f)
		f = AB.C.RegReplace(f, "\((.+?)\)", "$1")
		f = AB.C.RegReplace(f, "'(.+?)'", "$1")
		f = AB.C.RegReplace(f, """(.+?)""", "$1")
		f = Trim(f)
		SubTplPath = f
	End Function

	Private Function FixPath(ByVal p)
		p = Trim(p)
		p = AB.C.IIF(Left(p,1)="/", p, "/" & p)
		p = AB.C.IIF(Right(p,1)="/", Left(p,Len(p)-1), p)
		FixPath = p
	End Function

	'记录集转为字典
	Private Function RsToDic(ByVal data, ByVal dic)
		On Error Resume Next
		Dim i
		Select Case TypeName(data)
			Case "Recordset" '数据集
				For i = 0 To data.Fields.Count-1 '字段序列
					dic(Lcase(data.Fields(i).Name)) = data(i) & ""'字段名
					dic(i) = data(i) & ""'字段下标
				Next
			Case "Cls_AB_List" 'AspBox超级数组
				Dim Maps : Set Maps = data.Maps
				For i = 0 To data.End
					dic(Lcase(Maps(i))) = data(i) & ""
					dic(i) = data(i) & ""
				Next
			Case "Variant()" '数组
				For i = 0 To Ubound(data) '字段序列
					dic(i) = data(i) & ""'字段下标
				Next
		End Select
		Set RsToDic = dic
		On Error Goto 0
	End Function

	'更新DicLabel
	Private Sub UpdateDicLabel()
		On Error Resume Next
		Dim i, a, b, tmp
		For Each i In DicLabel
			If InStr(i,".") > 0 Then
				a = AB.C.CLeft(i,".")
				b = AB.C.CRight(i,".")
				If IsObject(DicLabel(a)) Then
					Set tmp = DicLabel(a)
					If IsObject(DicLabel(i)) Then Set tmp(b) = DicLabel(i) Else tmp(b) = DicLabel(i)
					Set DicLabel(a) = tmp
				End If
			End If
		Next
		On Error Goto 0
	End Sub

End Class
%>